#include "Calendar/GregorianFestivals.hpp"
#include "Astronomy/JDateTime.hpp"

#include <array>
#include <cmath>
#include <string>
#include <tuple>
#include <vector>

enum FestivalType : unsigned char
{
    // 重要喜庆日子名称(可将日子名称置红),放假日;
    Holiday,
    // 重要节日及纪念日;
    Important,
    // 其他节日及纪念日;
    Other,
};
// 月，第几个星期,星期几;
std::array<std::tuple<int, int, int, FestivalType, std::string>, 11> wFtv              = {{
    {5, 1, 3, FestivalType::Important, "世界麻风日"},
    {5, 2, 0, FestivalType::Other, "国际母亲节"},
    {5, 3, 0, FestivalType::Important, "全国助残日"},
    {6, 3, 0, FestivalType::Other, "父亲节"},
    {7, 3, 0, FestivalType::Other, "被奴役国家周"},
    {9, 3, 2, FestivalType::Important, "国际和平日"},
    {9, 4, 0, FestivalType::Other, "国际聋人节 世界儿童日"},
    {9, 5, 0, FestivalType::Important, "世界海事日"},
    {10, 1, 1, FestivalType::Other, "国际住房日"},
    {10, 1, 3, FestivalType::Important, "国际减轻自然灾害日(减灾日)"},
    {11, 4, 4, ::Important, "感恩节"},
}};

std::array<std::vector<std::tuple<int, FestivalType, int, int, std::string>>, 12> sFtv = {{
    // 01 月;
    {
        {1, FestivalType::Holiday, -1, -1, "元旦"},
    },
    // 02 月;
    {
        {2, FestivalType::Important, -1, -1, "世界湿地日"},
        {10, FestivalType::Other, -1, -1, "国际气象节"},
        {14, FestivalType::Important, -1, -1, "情人节"},
    },
    // 03 月;
    {
        {2, FestivalType::Other, -1, -1, "国际海豹日"},
        {3, FestivalType::Other, -1, -1, "全国爱耳日"},
        {5, FestivalType::Other, 1963, 9999, "学雷锋纪念日"},
        {8, FestivalType::Important, -1, -1, "妇女节"},
        {12, FestivalType::Important, -1, -1, "植树节"},
        {12, FestivalType::Other, 1925, 9999, "孙中山逝世纪念日"},
        {14, FestivalType::Other, -1, -1, "国际警察日"},
        {15, FestivalType::Important, 1983, 9999, "消费者权益日"},
        {17, FestivalType::Other, -1, -1, "中国国医节"},
        {17, FestivalType::Other, -1, -1, "国际航海日"},
        {21, FestivalType::Other, -1, -1, "世界森林日"},
        {21, FestivalType::Other, -1, -1, "消除种族歧视国际日"},
        {21, FestivalType::Other, -1, -1, "世界儿歌日"},
        {22, FestivalType::Important, -1, -1, "世界水日"},
        {23, FestivalType::Important, -1, -1, "世界气象日,"},
        {24, FestivalType::Other, 1982, 9999, "世界防治结核病日"},
        {25, FestivalType::Other, -1, -1, "全国中小学生安全教育日"},
        {30, FestivalType::Other, -1, -1, "巴勒斯坦国土日"},
    },
    // 04 月;
    {
        {1, FestivalType::Important, 1564, 9999, "愚人节"},
        {1, FestivalType::Other, -1, -1, "全国爱国卫生运动月(四月)"},
        {1, FestivalType::Other, -1, -1, "税收宣传月(四月)"},
        {7, FestivalType::Other, -1, -1, "世界卫生日"},
        {22, FestivalType::Important, -1, -1, "世界地球日"},
        {23, FestivalType::Other, -1, -1, "世界图书和版权日"},
        {24, FestivalType::Other, -1, -1, "亚非新闻工作者日"},
    },
    // 05 月;
    {
        {1, FestivalType::Holiday, 1889, 9999, "劳动节"},
        {4, FestivalType::Important, -1, -1, "青年节"},
        {5, FestivalType::Other, -1, -1, "碘缺乏病防治日"},
        {8, FestivalType::Other, -1, -1, "世界红十字日"},
        {12, FestivalType::Important, -1, -1, "国际护士节"},
        {15, FestivalType::Important, -1, -1, "国际家庭日"},
        {17, FestivalType::Other, -1, -1, "国际电信日"},
        {18, FestivalType::Other, -1, -1, "国际博物馆日"},
        {20, FestivalType::Other, -1, -1, "全国学生营养日"},
        {23, FestivalType::Other, -1, -1, "国际牛奶日"},
        {31, FestivalType::Important, -1, -1, "世界无烟日"},
    },
    // 06 月;
    {
        {1, FestivalType::Important, 1925, 9999, "国际儿童节"},
        {5, FestivalType::Other, -1, -1, "世界环境保护日"},
        {6, FestivalType::Other, -1, -1, "全国爱眼日"},
        {17, FestivalType::Other, -1, -1, "防治荒漠化和干旱日"},
        {23, FestivalType::Other, -1, -1, "国际奥林匹克日"},
        {25, FestivalType::Other, -1, -1, "全国土地日"},
        {26, FestivalType::Important, -1, -1, "国际禁毒日"},
    },
    // 07 月;
    {
        {1, FestivalType::Important, 1997, 9999, "香港回归纪念日"},
        {1, FestivalType::Important, 1921, 9999, "中共诞辰"},
        {1, FestivalType::Other, -1, -1, "世界建筑日"},
        {2, FestivalType::Other, -1, -1, "国际体育记者日"},
        {7, FestivalType::Other, 1937, 9999, "抗日战争纪念日"},
        {11, FestivalType::Important, -1, -1, "世界人口日"},
        {31, FestivalType::Other, -1, -1, "非洲妇女日"},
    },
    // 08 月;
    {
        {1, FestivalType::Important, 1927, 9999, "建军节"},
        {8, FestivalType::Other, -1, -1, "中国男子节(爸爸节)"},
    },
    // 09 月;
    {
        {3, FestivalType::Important, 1945, 9999, "抗日战争胜利纪念"},
        {8, FestivalType::Important, 1966, 9999, "国际扫盲日"},
        {8, FestivalType::Other, -1, -1, "国际新闻工作者日"},
        {9, FestivalType::Other, -1, -1, "毛泽东逝世纪念"},
        {10, FestivalType::Important, -1, -1, "中国教师节"},
        {14, FestivalType::Other, -1, -1, "世界清洁地球日"},
        {16, FestivalType::Other, -1, -1, "国际臭氧层保护日"},
        {18, FestivalType::Important, -1, -1, "九·一八事变纪念日"},
        {20, FestivalType::Other, -1, -1, "国际爱牙日"},
        {27, FestivalType::Other, -1, -1, "世界旅游日"},
        {28, FestivalType::Important, -1, -1, "孔子诞辰"},
    },
    // 10 月;
    {
        {1, FestivalType::Holiday, 1949, 9999, "国庆节"},
        {1, FestivalType::Other, -1, -1, "世界音乐日"},
        {1, FestivalType::Other, -1, -1, "国际老人节"},
        {2, FestivalType::Holiday, 1949, 9999, "国庆节假日"},
        {2, FestivalType::Important, -1, -1, "国际和平与民主自由斗争日"},
        {3, FestivalType::Holiday, 1949, 9999, "国庆节假日"},
        {4, FestivalType::Other, -1, -1, "世界动物日"},
        {6, FestivalType::Other, -1, -1, "老人节"},
        {8, FestivalType::Other, -1, -1, "全国高血压日"},
        {8, FestivalType::Other, -1, -1, "世界视觉日"},
        {9, FestivalType::Other, -1, -1, "世界邮政日"},
        {9, FestivalType::Other, -1, -1, "万国邮联日"},
        {10, FestivalType::Important, -1, -1, "辛亥革命纪念日"},
        {10, FestivalType::Other, -1, -1, "世界精神卫生日"},
        {13, FestivalType::Other, -1, -1, "世界保健日"},
        {13, FestivalType::Other, -1, -1, "国际教师节"},
        {14, FestivalType::Other, -1, -1, "世界标准日"},
        {15, FestivalType::Other, -1, -1, "国际盲人节(白手杖节)"},
        {16, FestivalType::Other, -1, -1, "世界粮食日"},
        {17, FestivalType::Other, -1, -1, "世界消除贫困日"},
        {22, FestivalType::Other, -1, -1, "世界传统医药日"},
        {24, FestivalType::Other, -1, -1, "联合国日"},
        {31, FestivalType::Other, -1, -1, "世界勤俭日"},
    },
    // 11 月;
    {
        {7, FestivalType::Other, 1917, 9999, "十月社会主义革命纪念日"},
        {9, FestivalType::Other, -1, -1, "中国记者日"},
        {9, FestivalType::Other, -1, -1, "全国消防安全宣传教育日"},
        {10, FestivalType::Holiday, 1949, 9999, "世界青年节"},
        {11, FestivalType::Important, -1, -1, "国际科学与和平周(本日所属的一周)"},
        {12, FestivalType::Holiday, 1949, 9999, "孙中山诞辰纪念日"},
        {14, FestivalType::Other, -1, -1, "世界糖尿病日"},
        {17, FestivalType::Other, -1, -1, "国际大学生节"},
        {17, FestivalType::Other, -1, -1, "世界学生节"},
        {20, FestivalType::Other, -1, -1, "彝族年"},
        {21, FestivalType::Other, -1, -1, "彝族年"},
        {21, FestivalType::Other, -1, -1, "世界问候日"},
        {21, FestivalType::Other, -1, -1, "世界电视日"},
        {22, FestivalType::Other, -1, -1, "彝族年"},
        {29, FestivalType::Other, -1, -1, "国际声援巴勒斯坦人民国际日"},
    },
    // 12 月;
    {
        {1, FestivalType::Important, 1988, 9999, "世界艾滋病日"},
        {3, FestivalType::Other, -1, -1, "世界残疾人日"},
        {5, FestivalType::Other, -1, -1, "国际经济和社会发展志愿人员日"},
        {8, FestivalType::Holiday, -1, -1, "国际儿童电视日"},
        {9, FestivalType::Important, -1, -1, "世界足球日"},
        {10, FestivalType::Other, -1, -1, "世界人权日"},

        {12, FestivalType::Important, -1, -1, "西安事变纪念日"},
        {13, FestivalType::Important, -1, -1, "南京大屠杀(1937年)纪念日"},
        {20, FestivalType::Other, -1, -1, "澳门回归纪念"},
        {21, FestivalType::Other, -1, -1, "国际篮球日"},
        {24, FestivalType::Important, -1, -1, "平安夜"},
        {25, FestivalType::Important, -1, -1, "圣诞节"},
        {26, FestivalType::Other, -1, -1, "毛泽东诞辰纪念"},
    },
}};

void GregorianFestivals::GetDayName(double jd, Festival &festival) noexcept
{
    JDateTime date(jd);

    //  月份;
    const int month         = date.getMonth();
    const int year          = date.getYear();
    const int day           = date.getDay();

    // 日星期;
    const int dayWeek       = date.getWeekDay();
    //  本月首日 星期;
    const int firstDayWeek  = JDateTime::getWeekday(year, month, 1);
    // 本月天数;
    const int daysOfMonth   = JDateTime::getDaysOfMonth(year, month);
    // 本日所在的周序号;
    const int weeki         = (int)floor((firstDayWeek + day) / 7);
    // 本月的总周数;
    const int numberOfWeeks = (int)floor((firstDayWeek + daysOfMonth - 1) / 7) + 1;

    for (auto &[day, type, startY, endY, name] : sFtv[month - 1])
    {
        if (day != date.getDay())
            continue;
        // 超出年限;
        if ((year != -1) && (year < startY) && (year > endY))
            continue;
        else if (year < 1550)
            continue;

        switch (type)
        {
        case Holiday :
        {
            festival.Fjia = true;
            festival.A += name;
            break;
        }
        case Important :
        {
            festival.B += name;
            break;
        }
        case Other :
        {
            festival.C += name;
            break;
        }
        }
    }

    int w1 = (dayWeek >= firstDayWeek) ? weeki + 1 : weeki;
    int w2 = (weeki == numberOfWeeks - 1) ? w1 + 5 : w1;

    for (auto &[m, weeki, week, type, name] : wFtv)
    {
        if (month != m)
            continue;
        if ((w1 != weeki) && (w2 != week))
            continue;
        switch (type)
        {
        case Holiday :
        {
            festival.Fjia = true;
            festival.A += name;
            break;
        }
        case Important :
        {
            festival.B += name;
            break;
        }
        case Other :
        {
            festival.C += name;
            break;
        }
        }
    }
}